package com.by.toolkit.platform;

import com.by.toolkit.consts.ByContextConst;
import com.by.toolkit.consts.GlobalConst;
import com.by.toolkit.utils.ByIfTrueUtil;
import com.by.toolkit.utils.SplitterUtil;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 上下文支持类
 *
 * @author YanBingHao
 * @since 2024/1/11
 */
public class ByContext {

    private static final ByContext INSTANCE = new ByContext();


    private static final ThreadLocal<Map<String, String>> THREAD_LOCAL = new InheritableThreadLocal<Map<String, String>>() {
        @Override
        protected Map<String, String> initialValue() {
            return Maps.newConcurrentMap();
        }
    };

    protected ByContext() {
    }

    public static void of(String k1, String v1) {
        Map<String, String> map = THREAD_LOCAL.get();
        map.put(k1, v1);
        MDC.put(k1, v1);
    }

    public static void of(String k1, String v1, String k2, String v2) {
        Map<String, String> map = THREAD_LOCAL.get();
        Map<String, String> k11 = Map.of(k1, v1, k2, v2);
        map.putAll(k11);
        k11.forEach(MDC::put);
    }

    public static void of(String k1, String v1, String k2, String v2, String k3, String v3) {
        Map<String, String> map = THREAD_LOCAL.get();
        Map<String, String> k11 = Map.of(k1, v1, k2, v2, k3, v3);
        map.putAll(k11);
        k11.forEach(MDC::put);
    }

    public static void of(String k1, String v1, String k2, String v2, String k3, String v3, String k4, String v4) {
        Map<String, String> map = THREAD_LOCAL.get();
        Map<String, String> k11 = Map.of(k1, v1, k2, v2, k3, v3, k4, v4);
        map.putAll(k11);
        k11.forEach(MDC::put);
    }

    public static void put(String key, String val) {
        Map<String, String> map = THREAD_LOCAL.get();
        map.put(key, val);
        MDC.put(key, val);
    }

    public static void putCorpCode(Long val) {
        put(ByContextConst.CORP_CODE, val.toString());
    }

    public static void putProjectId(Long val) {
        put(ByContextConst.PROJECT_ID, val.toString());
    }

    public static void putOperationUserId(Long val) {
        put(ByContextConst.OPERATION_USER_ID, val.toString());
    }

    public static void putIgnoreTenant() {
        put(ByContextConst.IGNORE_TENANT, GlobalConst.NEGATIVE_ONE_STR);
    }

    public static String get(String key) {
        Map<String, String> map = THREAD_LOCAL.get();
        return map.get(key);
    }

    public static Long getLong(String key) {
        String val = get(key);
        return ByIfTrueUtil.getIfTrue(StringUtils.isNotBlank(val), () -> Long.parseLong(val), null);
    }

    public static String getCorpCodeStr() {
        return get(ByContextConst.CORP_CODE);
    }

    public static Long getCorpCode() {
        String val = getCorpCodeStr();
        return ByIfTrueUtil.getIfTrue(StringUtils.isNotBlank(val), () -> Long.parseLong(val), null);
    }

    public static String getProjectIdStr() {
        return get(ByContextConst.PROJECT_ID);
    }

    public static Long getProjectId() {
        String val = getProjectIdStr();
        return ByIfTrueUtil.getIfTrue(StringUtils.isNotBlank(val), () -> Long.parseLong(val), null);
    }

    public static Long getOperationUserId() {
        String val = get(ByContextConst.OPERATION_USER_ID);
        return ByIfTrueUtil.getIfTrue(StringUtils.isNotBlank(val), () -> Long.parseLong(val), null);
    }

    public static boolean getIgnoreTenant() {
        return StringUtils.isNotBlank(get(ByContextConst.IGNORE_TENANT));
    }

    public static List<String> getIgnoreDyTableName() {
        String val = get(ByContextConst.NOT_USED_TABLE_NAME);
        return StringUtils.isNotBlank(val)
                ? SplitterUtil.EN_COMMA_SPLITTER.splitToList(val)
                : Collections.emptyList();
    }

    public static void putAll(Map<String, String> map) {
        THREAD_LOCAL.get().putAll(map);
        map.forEach(MDC::put);
    }

    public static Map<String, String> getAll() {
        Map<String, String> map = THREAD_LOCAL.get();
        return map.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    public static void remove(String key) {
        THREAD_LOCAL.get().remove(key);
        MDC.remove(key);
    }

    public static void removeProjectId() {
        remove(ByContextConst.PROJECT_ID);
    }

    public static void removeCorpCode() {
        remove(ByContextConst.CORP_CODE);
    }

    public static void removeOperationUserId() {
        remove(ByContextConst.OPERATION_USER_ID);
    }

    public static void removeIgnoreTenant() {
        remove(ByContextConst.IGNORE_TENANT);
    }

    public static void remove() {
        THREAD_LOCAL.remove();
        MDC.clear();
    }

    public static void effect(String key) {
        THREAD_LOCAL.get().remove(SplitterUtil.UNDERSCORE_JOINER.join(ByContextConst.INVALID_PREFIX, key));
    }

    public static void effectProjectId() {
        effect(ByContextConst.PROJECT_ID);
    }

    public static void effectCorpCode() {
        effect(ByContextConst.CORP_CODE);
    }

    public static void invalid(String key) {
        THREAD_LOCAL.get().put(SplitterUtil.UNDERSCORE_JOINER.join(ByContextConst.INVALID_PREFIX, key), GlobalConst.ZERO_STR);
    }

    public static void invalidProjectId() {
        invalid(ByContextConst.PROJECT_ID);
    }

    public static void invalidCorpCode() {
        invalid(ByContextConst.CORP_CODE);
    }

    public static boolean invalidFlag(String key) {
        return THREAD_LOCAL.get().containsKey(SplitterUtil.UNDERSCORE_JOINER.join(ByContextConst.INVALID_PREFIX, key));
    }

}
